package com.ybliang.plat.common.rpc.provider.netty;

import com.alibaba.fastjson.JSON;
import com.ybliang.plat.common.rpc.core.RpcRequest;
import com.ybliang.plat.common.rpc.core.RpcResponse;
import com.ybliang.plat.serviceapp.common.exception.BusinessException;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

@ChannelHandler.Sharable
public class NettyServerHandler extends ChannelInboundHandlerAdapter {

    private final Logger LOGGER = LoggerFactory.getLogger(NettyServerHandler.class);

    private final Map<String, Object> serviceMap;

    public NettyServerHandler(Map<String, Object> serviceMap) {
        this.serviceMap = serviceMap;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        LOGGER.info("NettyServerHandler->channelActive 客户端连接成功!" + ctx.channel().remoteAddress());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        LOGGER.info("NettyServerHandler->channelInactive 客户端断开连接!{}", ctx.channel().remoteAddress());
        ctx.channel().close();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        RpcRequest request = (RpcRequest) msg;
        if ("heartBeat".equals(request.getMethodName())) {
            LOGGER.info("客户端心跳信息..."+ctx.channel().remoteAddress());
        }else{
            LOGGER.info("NettyServerHandler->channelRead RPC客户端请求接口:{}, 方法名:{}",
                    request.getClassName(),
                    request.getMethodName());
            RpcResponse response = new RpcResponse();
            response.setId(request.getId());
            try {
                Object result = this.handler(request);
                response.setResult(result);
                LOGGER.info("RPC客户端请求接口:{}, 方法名:{}, result:{}",
                        request.getClassName(),
                        request.getMethodName(),
                        JSON.toJSONString(response));
            } catch (Throwable e) {

                if(e instanceof InvocationTargetException){
                    e = ((InvocationTargetException) e).getTargetException();
                }

                if(e instanceof BusinessException){
                    BusinessException businessException = (BusinessException) e;
                    response.setErrorCode(businessException.code);
                    response.setErrorMsg(businessException.message);
                }

                // 是JDK自带的异常，抛出系统异常
                String className = e.getClass().getName();
                if (className.startsWith("java.") || className.startsWith("javax.")) {
//                    ErrorHandler error = ErrorHandler.build();
                    response.setErrorCode(9999);
                    response.setErrorMsg("系统异常");
                }
//
                LOGGER.error("NettyServerHandler->channelRead->handler error...", e);
            }
            LOGGER.info("NettyServerHandler->channelRead response:{}", JSON.toJSONString(response));
            ctx.writeAndFlush(response);
        }
    }
    /**
     * 通过反射，执行本地方法
     * @param request
     * @return
     * @throws Throwable
     */
    private Object handler(RpcRequest request) throws Throwable {
        String className = request.getClassName();
        Object serviceBean = serviceMap.get(className);

        if (serviceBean!=null){
            Class<?> serviceClass = serviceBean.getClass();
            String methodName = request.getMethodName();
            Class<?>[] parameterTypes = request.getParameterTypes();
            Object[] parameters = request.getParameters();

            Method method = serviceClass.getMethod(methodName, parameterTypes);
            method.setAccessible(true);
            return method.invoke(serviceBean, getParameters(parameterTypes,parameters));
        }else{
            throw new Exception("未找到服务接口,请检查配置!:"+className+"#"+request.getMethodName());
        }
    }
    /**
     * 获取参数列表
     * @param parameterTypes
     * @param parameters
     * @return
     */
    private Object[] getParameters(Class<?>[] parameterTypes,Object[] parameters){
        if (parameters==null || parameters.length==0){
            return parameters;
        }else{
            Object[] new_parameters = new Object[parameters.length];
            for(int i=0;i<parameters.length;i++){
                new_parameters[i] = JSON.parseObject(parameters[i].toString(),parameterTypes[i]);
            }
            return new_parameters;
        }
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        LOGGER.info("NettyServerHandler->channelReadComplete...");
        ctx.flush();
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt)throws Exception {
        if (evt instanceof IdleStateEvent){
            IdleStateEvent event = (IdleStateEvent)evt;
            if (event.state()== IdleState.ALL_IDLE){
                LOGGER.info("客户端已超过60秒未读写数据,关闭连接.{}",ctx.channel().remoteAddress());
                ctx.channel().close();
            }
        }else{
            super.userEventTriggered(ctx, evt);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)   {
        LOGGER.error("NettyServerHandler->exceptionCaught...", cause);
        ctx.close();
    }
}
